package eu.liquify.ui {
	import flash.display.Bitmap;
	import flash.display.BlendMode;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Mouse;
	import flash.ui.MouseCursor;
	public class Demonstration extends Sprite {
		[Embed(source='assets/handCursor.png')]
		private var HandCursor:Class;
		private var cursorBmp:Bitmap;
		private var cursor:Sprite = new Sprite();
		
		private var item:UIItem;
		private var sim:ISimulatable;
		
		private var showing:Boolean = false;
		
		private var origin:Point = new Point();
		private var time:Number;
		
		private var overlay:Sprite = new Sprite();
		
		private var normalColor:ColorTransform = new ColorTransform();
		private var pressedColor:ColorTransform = new ColorTransform(1, 0.3, 0.3);
		
		private var sweepFrom:Point;
		private var sweepTo:Point;
		private var sweepDuration:Number;
		
		public function Demonstration() {
			overlay.addEventListener(MouseEvent.MOUSE_DOWN, overlayMouseEvent);
			overlay.addEventListener(MouseEvent.MOUSE_UP, overlayMouseEvent);
			overlay.addEventListener(MouseEvent.ROLL_OVER, overlayMouseEvent);
			overlay.addEventListener(MouseEvent.ROLL_OUT, overlayMouseEvent);
			overlay.addEventListener(MouseEvent.MOUSE_MOVE, overlayMouseEvent);
			
			/** Fast fps refresh rate flash player bug fix */
			var g:Graphics = cursor.graphics;
			g.clear();
			g.beginFill(0xFF0000, 0);
			g.drawRect(-100, -100, 200, 200);
		}
		
		private function overlayMouseEvent(e:MouseEvent):void {
			e.stopPropagation();
			e.preventDefault();
		}
		
		private function initItemDemo(item:UIItem, endFunction:Function):Boolean {
			if (!(item is ISimulatable)) throw new Error("Item "+item+" cannot be simulated because it does not implement ISimulatable.");
			
			if (showing) return false;
			showing = true;
			
			this.item = item;
			
			sim = item as ISimulatable;
			
			showOverlay();
			overlay.addEventListener(MouseEvent.MOUSE_DOWN, endFunction);
			
			return true;
		}
		private function endItemDemo(endFunction:Function):void {
			overlay.removeEventListener(MouseEvent.MOUSE_DOWN, endFunction);
			
			item = null;
			sim = null;
			hideOverlay();
			showing = false;
		}
		
		
		public function showHorizontalDrag(item:UIItem, p:Point):void {
			initDrag(item, p, runHorizontalMouse, hideHorizontalDrag);
		}
		private function hideHorizontalDrag(e:MouseEvent = null):void {
			endDrag(runHorizontalMouse, hideHorizontalDrag);
		}
		
		public function showDragSweep(item:UIItem, from:Point, to:Point, duration:Number = 100):void {
			sweepFrom = from;
			sweepTo = to;
			sweepDuration = duration;
			initDrag(item, from, runDragSweep, hideDragSweep);
		}
		private function hideDragSweep(e:MouseEvent = null):void {
			endDrag(runDragSweep, hideDragSweep);
			sweepFrom = sweepTo = null;
		}
		
		/*
		public function showClicks(item:UIItem, points:Vector.<Point>):void {
			var success:Boolean = initItemDemo(item, hideClicks);
			if (!success) return;
		}
		private function hideClicks(e:MouseEvent = null):void {
			
		}
		*/
		
		private function initDrag(item:UIItem, p:Point, runFunction:Function, endFunction:Function):void {
			var success:Boolean = initItemDemo(item, endFunction);
			if (!success) return;
			
			origin.x = p.x;
			origin.y = p.y;
			
			time = 0;
			initDragRun(runFunction);
			//addEventListener(Event.ENTER_FRAME, runHorizontalMouse);
		}
		private function endDrag(runFunction:Function, endFunction:Function):void {
			if (hasEventListener(Event.ENTER_FRAME)) {
				removeItemCursor();
				removeEventListener(Event.ENTER_FRAME, runFunction);
				sim.simulateEvent(new MouseEvent(MouseEvent.MOUSE_MOVE, true, false, origin.x, origin.y));
				sim.simulateEvent(new MouseEvent(MouseEvent.MOUSE_UP, true, false, origin.x, origin.y));
			} else if (stage.contains(cursor)) {
				stage.removeChild(cursor);
			}
			
			endItemDemo(endFunction);
			
			TweenNano.killTweensOf(cursor);
			destroyCursor();
			
			Mouse.show();
		}
		
		
		private function initCursor():void {
			cursorBmp = new HandCursor();
			cursorBmp.x = -cursorBmp.width/2;
			cursorBmp.y = -cursorBmp.height/2;
			cursor.addChild(cursorBmp);
		}
		private function destroyCursor():void {
			cursor.removeChild(cursorBmp);
			cursorBmp = null;
		}
		private function initDragRun(runFunction:Function):void {
			Mouse.hide();
			
			initCursor();
			stage.addChildAt(cursor, stage.numChildren-1);
			cursor.x = stage.mouseX;
			cursor.y = stage.mouseY;
			cursor.transform.colorTransform = normalColor;
			
			var p:Point = item.localToGlobal(origin);
			TweenNano.to(cursor, 1, { ease: Cubic.easeInOut, x: p.x, y: p.y,
				onComplete: function():void {
					sim.simulateEvent(new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, origin.x, origin.y));
					Mouse.cursor = MouseCursor.AUTO;
					
					stage.removeChild(cursor);
					addItemCursor();
					cursor.x = origin.x;
					cursor.y = origin.y;
					cursor.transform.colorTransform = pressedColor;
					
					addEventListener(Event.ENTER_FRAME, runFunction);
				}
			} );
		}
		private function stopDragRun(runFunction:Function, endFunction:Function):void {
			removeEventListener(Event.ENTER_FRAME, runFunction);
			sim.simulateEvent(new MouseEvent(MouseEvent.MOUSE_UP, true, false, origin.x, origin.y));
			
			cursor.transform.colorTransform = normalColor;
			
			removeItemCursor();
			stage.addChildAt(cursor, stage.numChildren-1);
			
			var p:Point = item.localToGlobal(new Point(cursor.x, cursor.y));
			cursor.x = p.x;
			cursor.y = p.y;
			TweenNano.to(cursor, 1, { ease: Cubic.easeInOut, x: stage.mouseX, y: stage.mouseY, onComplete: endFunction } );
		}
		
		private function addItemCursor():void {
			if (item is UIContainer) {
				(item as UIContainer).addRawChild(cursor);
			} else {
				item.addChild(cursor);
			}
		}
		private function removeItemCursor():void {
			if (item is UIContainer) {
				(item as UIContainer).removeRawChild(cursor);
			} else {
				item.removeChild(cursor);
			}
		}
		
		private function showOverlay():void {
			stage.addChild(overlay);
			redrawOverlay();
		}
		private function hideOverlay():void {
			overlay.graphics.clear();
			stage.removeChild(overlay);
		}
		
		private function redrawOverlay():void {
			var g:Graphics = overlay.graphics;
			g.clear();
			g.beginFill(0x000000, 0);
			g.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			
			/*
			var bounds:Rectangle = item.getBounds(stage);
			g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
			g.beginFill(0x000000, 0);
			g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
			*/
		}
		
		private function runHorizontalMouse(e:Event):void {
			var px:Number = origin.x+(Math.cos(Math.PI+time/20)+1)/2*Math.cos(time/5)*50;
			var py:Number = origin.y;
			
			cursor.x = px;
			cursor.y = py;
			
			sim.simulateEvent(new MouseEvent(MouseEvent.MOUSE_MOVE, true, false, px, py));
			
			time += 1;
			if (time > 40*3) {
				stopDragRun(runHorizontalMouse, hideHorizontalDrag);
			}
		}
		private function runDragSweep(e:Event):void {
			var delay:Number = 20;
			var f:Number = Math.min(1, Math.max(0, (time-delay)/sweepDuration));
			var p:Point = Point.interpolate(sweepFrom, sweepTo, 1-f);
			
			cursor.x = p.x;
			cursor.y = p.y;
			
			sim.simulateEvent(new MouseEvent(MouseEvent.MOUSE_MOVE, true, false, p.x, p.y));
			
			time += 1;
			if (time > sweepDuration+delay*2) {
				stopDragRun(runDragSweep, hideDragSweep);
			}
		}
	}

}